import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;

import com.googlecode.javacpp.Pointer;
import com.googlecode.javacv.*;
import com.googlecode.javacv.cpp.opencv_core.IplImage;

import static com.googlecode.javacv.cpp.opencv_core.*;
import static com.googlecode.javacv.cpp.opencv_imgproc.*;
import static com.googlecode.javacv.cpp.opencv_highgui.*;
import static javax.swing.JOptionPane.ERROR_MESSAGE;
import static javax.swing.JOptionPane.showMessageDialog;

import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.math.*;

/**
 * C to Java translation of the houghlines.c sample provided in the c sample directory of OpenCV 2.1,
 * using the JavaCV Java wrapper of OpenCV 2.2 developped by Samuel Audet.
 *
 * @author Jeremy Nicola
 * jeremy.nicola@gmail.com
 */
public class HoughCircles extends JFrame {

	IplImage src = null;
	IplImage dst = null;
	

    CanvasFrame source = new CanvasFrame("Source");

    private final JFileChooser fileChooser = new JFileChooser();

    /**
     * Component for displaying the image
     */
    private final JLabel imageView = new JLabel();

	
	private HoughCircles () throws HeadlessException{
		super("HoughCircles");
		
		final Action processAction = new AbstractAction("Process") {
            @Override
            public void actionPerformed(final ActionEvent e) {
                setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
                try {
                    // Process and update image display if image is loaded
                    if (src != null) {
                        processImage(src, dst);
                        imageView.setIcon(new ImageIcon(dst.getBufferedImage()));
                    } else {
                        showMessageDialog(HoughCircles.this, "Image not opened", getTitle(), ERROR_MESSAGE);
                    }
                } finally {
                    setCursor(Cursor.getDefaultCursor());
                }
            }
        };
        processAction.setEnabled(false);

        // Action performed when "Open Image" button is pressed
        final Action openImageAction = new AbstractAction("Open Image") {

            @Override
            public void actionPerformed(final ActionEvent e) {
                setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
                try {
                    // Load image and update display. If new image was not loaded do nothing.
                    final IplImage img = openImage();

                    if (img != null) {
                        src = img;
                        dst = img.clone();
                        imageView.setIcon(new ImageIcon(dst.getBufferedImage()));
                        processAction.setEnabled(true);
                    }
                } finally {
                    setCursor(Cursor.getDefaultCursor());
                }
            }
        };

        // Create button panel
        final JPanel buttonsPanel = new JPanel(new GridLayout(0, 1));
        buttonsPanel.add(new JButton(openImageAction));
        buttonsPanel.add(new JButton(processAction));
        
        
        //buttonsPanel.add(gaussian_slider);

        
        // Layout frame contents

        // Action buttons on the left
        final JPanel leftPane = new JPanel();
        leftPane.add(buttonsPanel);
        add(leftPane, BorderLayout.WEST);

        // Image display in the center
        final JScrollPane imageScrollPane = new JScrollPane(imageView);
        imageScrollPane.setPreferredSize(new Dimension(640, 480));
        add(imageScrollPane, BorderLayout.CENTER);
	}
	
	
	
	  /**
     * Ask user for location and open new image.
     *
     * @return Opened image or {@code null} if image was not loaded.
     */
    private IplImage openImage() {

        // Ask user for the location of the image file
        if (fileChooser.showOpenDialog(null) != JFileChooser.APPROVE_OPTION) {
            return null;
        }

        // Load the image
        final String path = fileChooser.getSelectedFile().getAbsolutePath();
        final IplImage newImage = cvLoadImage(path);
        if (newImage != null) {
            return newImage;
        } else {
            showMessageDialog(this, "Cannot open image file: " + path, getTitle(), ERROR_MESSAGE);
            return null;
        }
    }


    /**
     * Process image in place
     *
     * @param src image to process.
     */
    private void processImage(final IplImage src, final IplImage dst) {

        CvSeq circles = new CvSeq();


       IplImage tmp = cvCreateImage(cvGetSize(src), src.depth(), 1);
        cvCvtColor(src, tmp, CV_RGB2GRAY);
        cvCanny(tmp, tmp, 50, 200, 3);
    	cvSmooth(tmp, tmp, CV_GAUSSIAN, 9,9, 2.0, 0.0);
    	source.showImage(tmp);
        
        CvMemStorage mem = cvCreateMemStorage(0);
        circles = cvHoughCircles(tmp, mem, CV_HOUGH_GRADIENT, 1, 40.0, 60, 60,0,40);
        System.out.println(circles.total());

        for (int i = 0; i < circles.total(); i++)
        {
		 // round the floats to an int
		 CvPoint3D32f point = new CvPoint3D32f(cvGetSeqElem(circles, i));
		 
		 CvPoint center = cvPointFrom32f(new CvPoint2D32f(point.x(), point.y()));
		 int radius = Math.round(point.z());
		
		 System.out.println(radius);
		 System.out.printf("x: %d y: %d r: %d\n",center.x(),center.y(), radius);

		 // draw the circle center
		 cvCircle(dst, center, 3, CV_RGB(0,255,0), -1, 8, 0 );
		
		 // draw the circle outline
		 cvCircle(dst, center, radius+1, CV_RGB(0,0,255), 2, 8, 0 );
		
		 
		} 
        
    }


    /**
     * usage: java HoughLines imageDir\imageName TransformType
     */
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                final HoughCircles frame = new HoughCircles();
                frame.pack();
                // Mark for display in the center of the screen
                frame.setLocationRelativeTo(null);
                // Exit application when frame is closed.
                frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
                frame.setVisible(true);
            }
        });
        
    }
}
